package org.springblade.common.utils;

import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 慢SQL记录工具类 - 基于JdbcTemplate重构版本
 * 支持多环境配置和Spring管理的数据库连接
 *
 * @author: sharry, Jackey
 * @since: 2023-10-16
 */
@Component
@Slf4j
public class JdbcUtils implements ApplicationContextAware {

  private static ApplicationContext applicationContext;
  private static JdbcTemplate jdbcTemplate;
  private static DruidDataSource dataSource;

  // 配置参数（支持环境变量覆盖）
  private static String dbUrl;
  private static String dbUsername;
  private static String dbPassword;
  private static boolean enabled = true;

  @Override
  public void setApplicationContext(ApplicationContext context) {
    applicationContext = context;
  }

  @PostConstruct
  public void init() {
    initializeDataSourceAndTemplate();
  }

  /**
   * 初始化数据源和JdbcTemplate
   */
  private static void initializeDataSourceAndTemplate() {
    try {
      // 从环境变量或系统属性读取配置
      loadConfiguration();

      if (!enabled) {
        log.info("慢SQL记录功能已禁用");
        return;
      }

      // 创建数据源
      dataSource = new DruidDataSource();
      dataSource.setUrl(dbUrl);
      dataSource.setUsername(dbUsername);
      dataSource.setPassword(dbPassword);
      dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
      dataSource.setInitialSize(3);
      dataSource.setMaxActive(5);
      dataSource.setMaxWait(30000L);

      // 设置验证查询
      dataSource.setValidationQuery("select 1");
      dataSource.setTestWhileIdle(true);
      dataSource.setTestOnBorrow(false);
      dataSource.setTestOnReturn(false);

      // 创建JdbcTemplate
      jdbcTemplate = new JdbcTemplate(dataSource);

      log.info("慢SQL JdbcTemplate初始化成功，数据库URL: {}", maskUrl(dbUrl));

    } catch (Exception e) {
      log.error("初始化慢SQL JdbcTemplate失败，使用默认配置", e);
      initDefaultDataSourceAndTemplate();
    }
  }

  /**
   * 加载配置（支持环境变量和Spring Profile）
   */
  private static void loadConfiguration() {
    // 检查环境变量
    String envEnabled = System.getenv("SLOW_SQL_ENABLED");
    String envUrl = System.getenv("SLOW_SQL_DB_URL");
    String envUsername = System.getenv("SLOW_SQL_DB_USERNAME");
    String envPassword = System.getenv("SLOW_SQL_DB_PASSWORD");

    // 检查系统属性
    String propEnabled = System.getProperty("slow.sql.enabled");
    String propUrl = System.getProperty("slow.sql.db.url");
    String propUsername = System.getProperty("slow.sql.db.username");
    String propPassword = System.getProperty("slow.sql.db.password");

    // 检查Spring Profile
    String activeProfile = System.getProperty("spring.profiles.active");
    if (activeProfile == null) {
      activeProfile = System.getenv("SPRING_PROFILES_ACTIVE");
    }

    // 设置enabled状态
    if (envEnabled != null) {
      enabled = Boolean.parseBoolean(envEnabled);
    } else if (propEnabled != null) {
      enabled = Boolean.parseBoolean(propEnabled);
    }

    // 设置数据库配置
    if (envUrl != null) {
      dbUrl = envUrl;
      dbUsername = envUsername != null ? envUsername : "root";
      dbPassword = envPassword != null ? envPassword : "Erised2021!";
    } else if (propUrl != null) {
      dbUrl = propUrl;
      dbUsername = propUsername != null ? propUsername : "root";
      dbPassword = propPassword != null ? propPassword : "Erised2021!";
    } else {
      // 根据Spring Profile设置默认配置
      if ("dev".equals(activeProfile)) {
        dbUrl = "jdbc:mysql://221.4.198.163:3304/sida_maintain?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true";
      } else if ("test".equals(activeProfile)) {
        dbUrl = "jdbc:mysql://10.15.36.5:3306/sida_maintain?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true";
      } else {
        dbUrl = "jdbc:mysql://221.4.198.163:3306/sida_maintain?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true";
      }
      dbUsername = "root";
      dbPassword = "Erised2021!";
    }

    log.info("慢SQL配置加载完成 - 启用状态: {}, Profile: {}, URL: {}", enabled, activeProfile, maskUrl(dbUrl));
  }

  /**
   * 初始化默认数据源和JdbcTemplate（向后兼容）
   */
  private static void initDefaultDataSourceAndTemplate() {
    dataSource = new DruidDataSource();
    dataSource.setUrl("jdbc:mysql://221.4.198.163:3306/sida_maintain?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true");
    dataSource.setUsername("root");
    dataSource.setPassword("Erised2021!");
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    dataSource.setInitialSize(3);
    dataSource.setMaxActive(5);
    dataSource.setMaxWait(30000);
    dataSource.setValidationQuery("select 1");

    jdbcTemplate = new JdbcTemplate(dataSource);
    log.warn("使用默认慢SQL数据库配置");
  }

  /**
   * 获取JdbcTemplate实例，如果未初始化则进行初始化
   */
  private static JdbcTemplate getJdbcTemplate() {
    if (jdbcTemplate == null) {
      synchronized (JdbcUtils.class) {
        if (jdbcTemplate == null) {
          initializeDataSourceAndTemplate();
        }
      }
    }
    return jdbcTemplate;
  }

  /**
   * 屏蔽URL中的敏感信息用于日志输出
   */
  private static String maskUrl(String url) {
    if (url == null) {
      return "未配置";
    }
    return url.replaceAll("password=[^&]*", "password=***");
  }

  /**
   * 将慢SQL告警信息记录到数据库（新版本 - 使用JdbcTemplate）
   *
   * @param environment    环境信息
   * @param executionTime  执行时间（毫秒）
   * @param apiPath        接口路径
   * @param sqlStatement   SQL语句
   */
  public static void insertSlowSqlAlert(String environment, Long executionTime,
                                       String apiPath, String sqlStatement) {
    // 检查功能是否启用
    if (!enabled) {
      log.debug("慢SQL记录功能已禁用，跳过记录");
      return;
    }

    try {
      // 生成SQL指纹用于重复检查
      String sqlFingerprint = getSqlFingerprint(sqlStatement);

      if (!isDuplicationInNewTable(sqlFingerprint)) {
        JdbcTemplate template = getJdbcTemplate();
        if (template == null) {
          log.error("无法获取JdbcTemplate，跳过记录");
          return;
        }

        // 构建插入SQL
        String insertSql = "INSERT INTO blade_slow_sql_alert " +
                          "(id, environment, execution_time, api_path, sql_statement, alert_time) " +
                          "VALUES (?, ?, ?, ?, ?, ?)";

        // 生成ID和时间
        long id = System.currentTimeMillis() * 1000 + (long)(Math.random() * 1000);
        Date now = new Date();

        // 清理和提取纯净的API路径
        String cleanApiPath = extractCleanApiPath(apiPath);

        int result = template.update(insertSql,
            id, environment, executionTime, cleanApiPath, sqlStatement, new Timestamp(now.getTime()));

        log.info("慢SQL告警记录是否成功: {}, 执行时间: {}ms, 接口路径: {}",
                result > 0, executionTime, apiPath);
      } else {
        log.debug("该慢SQL已被记录，跳过重复记录");
      }
    } catch (DataAccessException e) {
      log.error("记录慢SQL告警异常", e);
    }
  }

  /**
   * 将SQL指纹和执行时间记录到数据库（兼容旧版本 - 使用JdbcTemplate）
   *
   * @param sqlFingerprint SQL指纹
   * @param time           执行时间（毫秒）
   */
  public static void executeQueryAndInsert(String sqlFingerprint, Long time) {
    try {
      if (!isDuplication(sqlFingerprint)) {
        JdbcTemplate template = getJdbcTemplate();
        if (template == null) {
          log.error("无法获取JdbcTemplate，跳过记录");
          return;
        }

        String insertSql = "INSERT INTO filter_log (time, ip) VALUES (?, ?)";
        int result = template.update(insertSql, time, sqlFingerprint);

        log.info("慢SQL记录是否成功: {}, SQL指纹: {}, 执行时间: {}ms",
                result > 0, sqlFingerprint, time);
      }
    } catch (DataAccessException e) {
      log.error("记录慢SQL异常", e);
    }
  }

  /**
   * 判断SQL指纹是否已存在（旧表 - 使用JdbcTemplate）
   *
   * @param sqlFingerprint SQL指纹
   * @return 是否已存在
   */
  public static boolean isDuplication(String sqlFingerprint) {
    try {
      JdbcTemplate template = getJdbcTemplate();
      if (template == null) {
        log.error("无法获取JdbcTemplate");
        return false;
      }

      String sql = "SELECT COUNT(*) FROM filter_log WHERE ip = ?";
      Integer count = template.queryForObject(sql, Integer.class, sqlFingerprint);
      return count != null && count > 0;

    } catch (DataAccessException e) {
      log.error("查询SQL指纹异常", e);
      return false;
    }
  }

  /**
   * 检查新表中是否存在重复的SQL指纹（使用JdbcTemplate）
   *
   * @param sqlFingerprint SQL指纹
   * @return 是否已存在
   */
  private static boolean isDuplicationInNewTable(String sqlFingerprint) {
    try {
      JdbcTemplate template = getJdbcTemplate();
      if (template == null) {
        log.error("无法获取JdbcTemplate");
        return false;
      }

      // 查询新表中是否存在相同的SQL指纹
      String sql = "SELECT COUNT(*) FROM blade_slow_sql_alert WHERE sql_statement = ?";
      Integer count = template.queryForObject(sql, Integer.class, sqlFingerprint);
      return count != null && count > 0;

    } catch (DataAccessException e) {
      log.debug("查询新表SQL指纹异常，回退到旧表查询: {}", e.getMessage());
      // 如果新表查询失败，回退到旧表查询
      return isDuplication(sqlFingerprint);
    }
  }

  /**
   * 提取纯净的API路径
   * 处理各种可能的格式，确保只返回URL路径部分
   *
   * @param apiPath 原始API路径字符串
   * @return 纯净的URL路径
   */
  private static String extractCleanApiPath(String apiPath) {
    if (apiPath == null || apiPath.trim().isEmpty()) {
      return "未知路径";
    }

    String cleanPath = apiPath.trim();

    // 处理包含"接口路径: "前缀的情况
    if (cleanPath.startsWith("接口路径: ")) {
      cleanPath = cleanPath.substring("接口路径: ".length());
    }

    // 处理包含换行符的情况，只保留第一行
    if (cleanPath.contains("\n")) {
      cleanPath = cleanPath.split("\n")[0].trim();
    }

    // 处理包含回车符的情况
    if (cleanPath.contains("\r")) {
      cleanPath = cleanPath.split("\r")[0].trim();
    }

    // 处理可能包含其他分隔符的情况（如制表符、多个空格等）
    cleanPath = cleanPath.replaceAll("\\s+", " ").trim();

    // 验证是否为有效的URL路径格式
    if (cleanPath.isEmpty()) {
      return "未知路径";
    }

    // 如果不是以/开头的路径，但包含常见的路径字符，尝试提取
    if (!cleanPath.startsWith("/") && cleanPath.contains("/")) {
      // 处理完整URL的情况（如 http://localhost:8080/api/test）
      if (cleanPath.startsWith("http://") || cleanPath.startsWith("https://")) {
        // 查找第三个/开始的部分（协议://域名/路径）
        int protocolEnd = cleanPath.indexOf("://");
        if (protocolEnd >= 0) {
          int pathStart = cleanPath.indexOf("/", protocolEnd + 3);
          if (pathStart >= 0) {
            cleanPath = cleanPath.substring(pathStart);
          }
        }
      } else {
        // 查找第一个/开始的部分
        int slashIndex = cleanPath.indexOf("/");
        if (slashIndex >= 0) {
          cleanPath = cleanPath.substring(slashIndex);
        }
      }
    }

    // 移除可能的查询参数和片段标识符（保持路径的纯净性）
    if (cleanPath.contains("?")) {
      cleanPath = cleanPath.split("\\?")[0];
    }
    if (cleanPath.contains("#")) {
      cleanPath = cleanPath.split("#")[0];
    }

    // 最终验证和清理
    cleanPath = cleanPath.trim();
    if (cleanPath.isEmpty() || cleanPath.equals("/")) {
      return cleanPath.isEmpty() ? "未知路径" : "/";
    }

    log.debug("API路径清理: 原始='{}' -> 清理后='{}'", apiPath, cleanPath);

    return cleanPath;
  }

  /**
   * 生成SQL指纹（去除参数值的SQL模板）
   *
   * @param sql 原始SQL
   * @return SQL指纹
   */
  private static String getSqlFingerprint(String sql) {
    if (sql == null || sql.trim().isEmpty()) {
      return "";
    }

    // 简单的SQL指纹生成：将参数值替换为占位符
    return sql.replaceAll("'[^']*'", "?")  // 替换字符串参数
              .replaceAll("\\b\\d+\\b", "?")  // 替换数字参数
              .replaceAll("\\s+", " ")        // 标准化空格
              .trim();
  }

  /**
   * 获取所有SQL指纹列表（用于批量检查 - 使用JdbcTemplate）
   *
   * @return SQL指纹列表
   */
  public static List<String> getAllSqlFingerprints() {
    try {
      JdbcTemplate template = getJdbcTemplate();
      if (template == null) {
        log.error("无法获取JdbcTemplate");
        return new ArrayList<>();
      }

      String sql = "SELECT ip FROM filter_log";
      return template.queryForList(sql, String.class);

    } catch (DataAccessException e) {
      log.error("查询所有SQL指纹异常", e);
      return new ArrayList<>();
    }
  }

  /**
   * 批量检查SQL指纹是否存在（使用JdbcTemplate）
   *
   * @param sqlFingerprints SQL指纹列表
   * @return 存在的SQL指纹列表
   */
  public static List<String> batchCheckDuplication(List<String> sqlFingerprints) {
    if (sqlFingerprints == null || sqlFingerprints.isEmpty()) {
      return new ArrayList<>();
    }

    try {
      JdbcTemplate template = getJdbcTemplate();
      if (template == null) {
        log.error("无法获取JdbcTemplate");
        return new ArrayList<>();
      }

      // 构建IN查询
      StringBuilder sqlBuilder = new StringBuilder("SELECT ip FROM filter_log WHERE ip IN (");
      for (int i = 0; i < sqlFingerprints.size(); i++) {
        if (i > 0) sqlBuilder.append(",");
        sqlBuilder.append("?");
      }
      sqlBuilder.append(")");

      return template.queryForList(sqlBuilder.toString(), String.class, sqlFingerprints.toArray());

    } catch (DataAccessException e) {
      log.error("批量查询SQL指纹异常", e);
      return new ArrayList<>();
    }
  }

  /**
   * 获取数据源状态信息
   *
   * @return 数据源状态信息
   */
  public static String getDataSourceStatus() {
    if (dataSource == null) {
      return "数据源未初始化";
    }

    try {
      return String.format("数据源状态 - 活跃连接: %d, 最大连接: %d, URL: %s",
          dataSource.getActiveCount(),
          dataSource.getMaxActive(),
          maskUrl(dataSource.getUrl()));
    } catch (Exception e) {
      return "获取数据源状态失败: " + e.getMessage();
    }
  }

  /**
   * 测试数据库连接
   *
   * @return 连接是否成功
   */
  public static boolean testConnection() {
    try {
      JdbcTemplate template = getJdbcTemplate();
      if (template == null) {
        return false;
      }

      template.queryForObject("SELECT 1", Integer.class);
      log.info("慢SQL数据库连接测试成功");
      return true;

    } catch (DataAccessException e) {
      log.error("慢SQL数据库连接测试失败", e);
      return false;
    }
  }
}
